/*
 * SoftwareSAR - 1.0
 */
package br.com.cpqd.ssar.geradormalha.gui;

import br.com.cpqd.ssar.geradormalha.Eixo;
import br.com.cpqd.ssar.mediador.RequisicaoServicos;
import br.com.cpqd.ssar.utilitarias.Material;
import com.sun.opengl.util.GLUT;
import java.awt.Color;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.awt.event.MouseWheelEvent;
import java.awt.event.MouseWheelListener;
import java.nio.FloatBuffer;
import java.util.ArrayList;
import java.util.List;
import javax.media.opengl.GL;
import javax.media.opengl.GLAutoDrawable;
import javax.media.opengl.GLCanvas;
import javax.media.opengl.GLEventListener;
import javax.media.opengl.glu.GLU;

/**
 * Classe que faz a Renderização da Malha na Janela
 * @author Rafael Buck
 * @version 1.1
 */
public class RenderizadorMalha implements GLEventListener, KeyListener,
        MouseListener, MouseMotionListener, MouseWheelListener {

    //Valor a ser multiplicado para obter o tamanho da proporção da malha
    private float fatorX, fatorY, fatorZ;

    //Lista de todos Materiais existentes na malha
    private List<VisibilidadeMaterialVO> materiais;

    //Valores de referencia do corte transversal
    private boolean statusGridDominio = true;        //Mostra/esconde a grid do dominio computacional
    private boolean statusCorteReferencia = true;    //Mostra/esconde a "linha" onde o corte será feito
    private boolean statusCorteComMouse = false;     //Corte com o mouse ativado/desativado
    private boolean statusPosicaoValidaMouse = true; //Mouse está numa posicação válida/invalida para fazer o corte
    private boolean corteReferenciaAlterado = false; //Especifica se o valor do corte foi alterado para ser redesenhada
    private boolean corteReferenciaCalculado = true; //Especifica se a coordenada real do corte ja foi calculada a partir da coordenado do mouse
    private float valor1, valor2;                    //Valor do local onde será feito o corte
    private byte valorAtual = 1;                     //Valor atual que o click do mouse irá alterar (1 ou 2)
    private MouseEvent e;                            //Valor do mouse do local onde será feito o corte
    private Eixo eixo;                               //Eixo que será cortado
    // Valores reais do corte transversal (local onde o corte será feito na malha)
    private float dominioX1, dominioY1, dominioZ1;
    private float dominioX2, dominioY2, dominioZ2;

    // Especifica se a malha foi cortada ou a visibilidade alterada para ser redesenhada
    private boolean malhaAlterada = true;

    // Steps de rotação e translado
    private final static float ROTACAO_STEP = 1.0f;
    private final static float POSICAO_STEP = 0.5f;
    private final static float ZOOM_STEP = 0.5f;

    // Configuração inicial
    private float RotacaoInicialX = -70.0f;
    private float RotacaoInicialY = 0.0f;
    private float RotacaoInicialZ = 0.0f;
    private float PosicaoInicialX = 0.0f;
    private float PosicaoInicialY = 0.0f;
    private float PosicaoInicialZ = -40.0f;
    private final static boolean STATUS_GRID_INICIAL = true;

    //Limites de rotação e translado durante a seleção do local do
    //corte da malha utilizando o mouse (valores iniciados considerando eixo X)
    //* Limites da rotação
    private float rotacaoXMaximaCorte = 90.0f;
    private float rotacaoXMinimaCorte = 5.0f;
    private float rotacaoYMaximaCorte = 45.0f;
    private float rotacaoYMinimaCorte = -45.0f;
    private float rotacaoZMaximaCorte = 45.0f;
    private float rotacaoZMinimaCorte = -45.0f;
    //* Limites do translado
    private float posicaoXMaximaCorte = 64;
    private float posicaoXMinimaCorte = -64;
    private float posicaoYMaximaCorte = 64.0f;
    private float posicaoYMinimaCorte = 0.0f;
    private float posicaoZMaximaCorte = 0.0f;
    private float posicaoZMinimaCorte = -98.0f;

    /**
     * Interface da Requisição de Serviços
     */
    private RequisicaoServicos requisicaoServicos;
    /**
     * Classe que Gera a Malha
     */
    private InterfaceRenderizacaoMalha malhaGerada;
    /**
     * GL
     */
    private GL gl;
    /**
     * GLU
     */
    private GLU glu = new GLU();
    /**
     * GLUT
     */
    private GLUT glut = new GLUT();
    /**
     * GLCanvas
     */
    private GLCanvas gLCanvas;

    //Listas Pré-Compiladas
    private int listaMalha;
    private int listaGrid;
    private int listaDominio;
    private int listaCorte;

    //Rotação e Translado
    private float rotacaoX = RotacaoInicialX;
    private float rotacaoY = RotacaoInicialY;
    private float rotacaoZ = RotacaoInicialZ;
    private float posicaoX = PosicaoInicialX;
    private float posicaoY = PosicaoInicialY;
    private float posicaoZ = PosicaoInicialZ;

    //Matrizes
    private int[] viewport = new int[4];
    double[] modelMatrix = new double[16];
    double[] projMatrix = new double[16];

    //Iluminação da cena
    private float[] luzAmbiente = {0.2f,0.2f,0.2f,1.0f};

    // Configurações da grid
    private Color corGrid = new Color(204, 204, 204);
    private int tamGrid = 64;
    private boolean statusGrid = STATUS_GRID_INICIAL;

    /**
     * Método Construtor
     * @param malhaGerada InterfaceRenderizacaoMalha
     * @param requisicaoServicos RequisicaoServicos
     * @param gLCanvas GLCanvas
     */
    public RenderizadorMalha(InterfaceRenderizacaoMalha malhaGerada, RequisicaoServicos requisicaoServicos, GLCanvas gLCanvas) {
        this.malhaGerada = malhaGerada;
        this.requisicaoServicos = requisicaoServicos;
        this.gLCanvas = gLCanvas;
    }

    @Override
    /* Called by drawable to initiate drawing. */
    public void display(GLAutoDrawable drawable) {
        gl = drawable.getGL();
        
        gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT);

        gl.glMatrixMode(GL.GL_MODELVIEW);
        gl.glLoadIdentity();

        gl.glTranslatef(posicaoX, posicaoY, posicaoZ);

        gl.glRotatef(rotacaoX, 1.0f, 0.0f, 0.0f);
        gl.glRotatef(rotacaoY, 0.0f, 1.0f, 0.0f);
        gl.glRotatef(rotacaoZ, 0.0f, 0.0f, -1.0f);

        // Calcula a posição do OpenGL a partir da posição do mouse
        boolean efetuouCalculo = false;
        if (statusCorteComMouse){
            if (corteReferenciaAlterado && !corteReferenciaCalculado){
                corteReferenciaCalculado = true;
                efetuouCalculo = true;
                calculaValoresMouse();
                gLCanvas.display();
            }
        }

        // Verifica se o calculo foi feito para evitar recursividade
        if (!efetuouCalculo){
            // renderização da malha
            if (malhaGerada != null) {
                //Se foi cortada ou a visibilidade de algum material alterada, redesenha
                if (malhaAlterada){
                    geraMalhaPreCompilada(dominioX1, dominioX2, dominioY1, dominioY2, dominioZ1, dominioZ2);
                    malhaAlterada = false;
                }
                //Renderiza
                if (gl.glIsList(listaMalha)){
                    gl.glCallList(listaMalha);
                }
            }
            // renderiza a grid
            if (statusGrid) {
                if (gl.glIsList(listaGrid)) {
                    gl.glCallList(listaGrid);
                }
            }
            //renderiza a grid do dominio computacional
            if (statusGridDominio) {
                if (gl.glIsList(listaDominio)) {
                    gl.glCallList(listaDominio);
                }
            }
            //renderiza as referencias dos cortes transversais
            if (statusCorteReferencia){
                if (corteReferenciaAlterado){
                    geraReferenciaCorte();
                    corteReferenciaAlterado = false;
                }
                if (gl.glIsList(listaCorte)){
                    gl.glCallList(listaCorte);
                }
            }
        }
    }

    //A partir das coordenadas X e Y da tela onde o mouse está posicionado,
    //obtém a posição Z, e calcula a coordenada X, Y e Z real do OpenGL
    private void calculaValoresMouse(){
        int listaLimiares = gl.glGenLists(1);
        gl.glNewList(listaLimiares, gl.GL_COMPILE);

        //Cria os limiares que serão utilizados como referencia para obter a
        //posicao Z do local onde o mouse está posicionado
        gl.glColor4f(0.0f, 0.0f, 0.0f, 0.3f);
        gl.glLineWidth(1.0f);

        if (eixo.equals(Eixo.X) || eixo.equals(Eixo.Y)){
            //Piso (sobre a grid)
            gl.glBegin(GL.GL_QUADS);
            gl.glVertex3f(-tamGrid/2, -tamGrid/2, 0);
            gl.glVertex3f(tamGrid/2, -tamGrid/2, 0);
            gl.glVertex3f(tamGrid/2, tamGrid/2, 0);
            gl.glVertex3f(-tamGrid/2, tamGrid/2, 0);
            gl.glEnd();
        }
        if (eixo.equals(Eixo.X) || eixo.equals(Eixo.Y)){
            //Parede traseira
            gl.glBegin(GL.GL_QUADS);
            gl.glVertex3f(-tamGrid/2, tamGrid/2, tamGrid);
            gl.glVertex3f(tamGrid/2, tamGrid/2, tamGrid);
            gl.glVertex3f(tamGrid/2, tamGrid/2, 0);
            gl.glVertex3f(-tamGrid/2, tamGrid/2, 0);
            gl.glEnd();
        }
        if (eixo.equals(Eixo.Y)){
            //Parede frente
            gl.glBegin(GL.GL_QUADS);
            gl.glVertex3f(-tamGrid/2, -tamGrid/2, tamGrid);
            gl.glVertex3f(tamGrid/2, -tamGrid/2, tamGrid);
            gl.glVertex3f(tamGrid/2, -tamGrid/2, 0);
            gl.glVertex3f(-tamGrid/2, -tamGrid/2, 0);
            gl.glEnd();
        }
        if (eixo.equals(Eixo.X) || eixo.equals(Eixo.Y)){
            //Parede esquerda
            gl.glBegin(GL.GL_QUADS);
            gl.glVertex3f(-tamGrid/2, tamGrid/2, tamGrid);
            gl.glVertex3f(-tamGrid/2, -tamGrid/2, tamGrid);
            gl.glVertex3f(-tamGrid/2, -tamGrid/2, 0);
            gl.glVertex3f(-tamGrid/2, tamGrid/2, 0);
            gl.glEnd();
        }
        if (eixo.equals(Eixo.X)){
            //Parede direita
            gl.glBegin(GL.GL_QUADS);
            gl.glVertex3f(tamGrid/2, tamGrid/2, tamGrid);
            gl.glVertex3f(tamGrid/2, -tamGrid/2, tamGrid);
            gl.glVertex3f(tamGrid/2, -tamGrid/2, 0);
            gl.glVertex3f(tamGrid/2, tamGrid/2, 0);
            gl.glEnd();
        }
        if (eixo.equals(Eixo.Z)){
            //Parede traseira fixando Y em 0
            gl.glBegin(GL.GL_QUADS);
            gl.glVertex3f(-tamGrid, 0, tamGrid);
            gl.glVertex3f(tamGrid, 0, tamGrid);
            gl.glVertex3f(tamGrid, 0, -tamGrid);
            gl.glVertex3f(-tamGrid, 0, -tamGrid);
            gl.glEnd();
        }
        
        gl.glEndList();
        if (gl.glIsList(listaLimiares)){
            gl.glCallList(listaLimiares);
        }

        if (e != null) {
            //Obtém as matrizes
            gl.glGetIntegerv(GL.GL_VIEWPORT, viewport, 0);
            gl.glGetDoublev(GL.GL_MODELVIEW_MATRIX, modelMatrix, 0);
            gl.glGetDoublev(GL.GL_PROJECTION_MATRIX, projMatrix, 0);

            // Variavel utilizada para guarda as coordenadas de X, Y e Z real
            double wcoord[] = new double[4];

            //Obtém a posição de X e Y do mouse
            int winX = e.getX();
            int winY = viewport[3] - e.getY();

            //Obtém a posição de Z do objeto que mouse está tocando com relação
            //a camera (limiares criados acima)
            double winZ = 0;
            FloatBuffer z = FloatBuffer.allocate(1);
            z.clear();
            gl.glReadPixels(winX, winY, 1, 1, GL.GL_DEPTH_COMPONENT, GL.GL_FLOAT, z);
            z.rewind();
            winZ = z.get();
            //verifica se o mouse está posicionado numa posição válida, ou seja,
            //sob os limiares de refencia
            if (winZ == 1.0){
                statusPosicaoValidaMouse = false;
            }else{
                statusPosicaoValidaMouse = true;
                //A partir da posição do mouse na tela, obtém a posição real no OpenGL
                glu.gluUnProject(winX, winY, winZ, modelMatrix, 0, projMatrix, 0, viewport, 0, wcoord, 0);

                if (eixo.equals(Eixo.X)){
                    if (valorAtual == 1){
                        valor1 = (float) wcoord[0];
                    }else if (valorAtual == 2){
                        valor2 = (float) wcoord[0];
                    }
                }else if (eixo.equals(Eixo.Y)){
                    if (valorAtual == 1){
                        valor1 = (float) wcoord[1];
                    }else if (valorAtual == 2){
                        valor2 = (float) wcoord[1];
                    }
                }else if (eixo.equals(Eixo.Z)){
                    if (valorAtual == 1){
                        valor1 = (float) wcoord[2];
                    }else if (valorAtual == 2){
                        valor2 = (float) wcoord[2];
                    }
                }
            }
        }

        if (gl.glIsList(listaLimiares)){
            gl.glDeleteLists(listaLimiares,1);
        }
    }

    public void displayChanged(GLAutoDrawable drawable, boolean modeChanged, boolean deviceChanged) {
//        System.out.println("displayChanged");
    }
    /**
     * Inicializa a Máquina de Estados
     * @param drawable GLAutoDrawable
     */
    public void init(GLAutoDrawable drawable) {
        // Obtem referência ao GL
        gl = drawable.getGL();
        // Especifica Cor de Fundo
        gl.glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
        // Pinta o Fundo da Tela com a Cor Escolhida
        gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT);
        // Habilita a definição da cor do material a partir da cor corrente
        gl.glEnable(GL.GL_COLOR_MATERIAL);
        // Habilita o depth-buffer
        gl.glEnable(GL.GL_DEPTH_TEST);
        // Habilita o modelo de colorização de Gouraud
        gl.glShadeModel(gl.GL_SMOOTH);
        
        // Transparência
        gl.glEnable(gl.GL_BLEND);
        gl.glBlendFunc(gl.GL_SRC_ALPHA, gl.GL_ONE_MINUS_SRC_ALPHA);

        // Estabelece os parâmetros do modelo de iluminação ambiente
        gl.glLightModelfv(gl.GL_LIGHT_MODEL_AMBIENT, luzAmbiente, 0 );
        //Habilita uso de iluminação
        gl.glEnable(GL.GL_LIGHTING);
        // Habilita luz de número 0
        gl.glEnable(GL.GL_LIGHT0);

        // Adiciona a grid
        geraGrid();
        geraGridDominio();

        // compila a malha
        if (malhaGerada != null) {
            //defini que os cortes da malha serão nas extremidades (ou seja, não sera cortada)
            dominioX1 = malhaGerada.getXMin();
            dominioY1 = malhaGerada.getYMin();
            dominioZ1 = malhaGerada.getZMin();
            dominioX2 = malhaGerada.getXMax();
            dominioY2 = malhaGerada.getYMax();
            dominioZ2 = malhaGerada.getZMax();

            //inicia as linhas de Referencia do corte da malha nas extremidades do eixo X
            valor1 = malhaGerada.getXMin();
            valor2 = malhaGerada.getXMax();
            eixo = Eixo.X;

            fatorX = malhaGerada.getNx() / (malhaGerada.getXMax() - malhaGerada.getXMin());
            fatorY = malhaGerada.getNy() / (malhaGerada.getYMax() - malhaGerada.getYMin());
            fatorZ = malhaGerada.getNz() / (malhaGerada.getZMax() - malhaGerada.getZMin());

            // Obtém a relação de todos materiais da malha
            getMateriais();
        }
    }
    /**
     * Define a Janela de Visualização 2D (Inicializa)
     * @param autoDrawable GLAutoDrawable
     * @param x int
     * @param y int
     * @param width int
     * @param height int
     */
    public void reshape(GLAutoDrawable autoDrawable, int x, int y, int width, int height) {
        // Obtem referência ao GL
        gl = autoDrawable.getGL();
        // Evita divisão por zero
        if (height <= 0) {
            height = 1;
        }
        float h = (float) width / (float) height;
        gl.glViewport(0,0,width,height);
        // Seleciona matriz de projeção
        gl.glMatrixMode(GL.GL_PROJECTION);
        gl.glLoadIdentity();
        // Especifica a Projeção Perspectiva (angulo,aspecto,zMin,zMax))
        glu.gluPerspective(45.0f, h, 0.1, 200.0);
        // Seleciona matriz do modelo
        gl.glMatrixMode(GL.GL_MODELVIEW);
        gl.glLoadIdentity();
    }
    /**
     * Gera corte na malha gerada
     */
    public void geraCorteTransversal(float x1, float x2, float y1, float y2, float z1, float z2){
        this.malhaAlterada = true;
        this.dominioX1 = x1;
        this.dominioY1 = y1;
        this.dominioZ1 = z1;
        this.dominioX2 = x2;
        this.dominioY2 = y2;
        this.dominioZ2 = z2;
        this.gLCanvas.display();
    }
    /**
     * Altera posição da "linha" de referencia do local onde corte será feito
     */
    public void alteraReferenciaCorteTransversal(float v1, float v2, Eixo eixo){
        corteReferenciaAlterado = true;
        this.e = null;
        this.valor1 = v1;
        this.valor2 = v2;
        this.eixo = eixo;
        this.gLCanvas.display();
    }
    /**
     * Altera posição da "linha" de referencia do local onde corte será feito
     */
    public void alteraReferenciaCorteTransversal(MouseEvent e, Eixo eixo){
        corteReferenciaAlterado = true;
        corteReferenciaCalculado = false;
        this.e = e;
        this.eixo = eixo;
        this.gLCanvas.display();
    }
    /**
     * Altera a visibilidade dos materiais da malha gerada
     */
    public void alteraVisibilidade(List<VisibilidadeMaterialVO> materiais){
        this.malhaAlterada = true;
        this.materiais = materiais;
        this.gLCanvas.display();
    }
    /**
     * Gera uma Pré Compilação do Display da Malha (Aumenta Performance)
     */
    private void geraMalhaPreCompilada(Float x1, Float x2, Float y1, Float y2, Float z1, Float z2) {
        listaMalha = gl.glGenLists(1);
        gl.glNewList(listaMalha, gl.GL_COMPILE);

        float ix1, iy1, iz1;
        float ix2, iy2, iz2;

        ix1 = ((x1 == null) ? malhaGerada.getXMin() : x1) + Math.abs(malhaGerada.getXMin());
        iy1 = ((y1 == null) ? malhaGerada.getYMin() : y1) + Math.abs(malhaGerada.getYMin());
        iz1 = ((z1 == null) ? malhaGerada.getZMin() : z1) + Math.abs(malhaGerada.getZMin());

        ix2 = ((x2 == null) ? malhaGerada.getXMax() : x2) + Math.abs(malhaGerada.getXMin());
        iy2 = ((y2 == null) ? malhaGerada.getYMax() : y2) + Math.abs(malhaGerada.getYMin());
        iz2 = ((z2 == null) ? malhaGerada.getZMax() : z2) + Math.abs(malhaGerada.getZMin());

        // Coordenadas do cubo
        float dx, dy, dz;
        boolean conditionX, conditionY, conditionZ;
        int number = 0;
        // Material do Cubo
        Material material;
        Color cor;
        float R, G, B;
        int idMaterial;
        for (int k = (int) (iz1 * fatorZ); k < (int) (iz2 * fatorZ); k++) {
            for (int j = (int) (iy1 * fatorY); j < (int) (iy2 * fatorY); j++) {
                for (int i = (int) (ix1 * fatorX); i < (int) (ix2 * fatorX); i++) {
                    gl.glPushMatrix();
                    // Acerta a Posição do Desenho
                    dx = (malhaGerada.getXMin() + i * malhaGerada.getDx()) + (malhaGerada.getDx() * 0.5f);
                    dy = (malhaGerada.getYMin() + j * malhaGerada.getDy()) + (malhaGerada.getDy() * 0.5f);
                    dz = (malhaGerada.getZMin() + k * malhaGerada.getDz()) + (malhaGerada.getDz() * 0.5f);
                    gl.glTranslatef(dx, dy, dz);
                    idMaterial = malhaGerada.obterMaterialCubo(i, j, k);
                    if (idMaterial == 1) {
                        // ar
                    } else {
                        conditionX = (i - 1 > 0) && (i + 1 < malhaGerada.getNx());
                        conditionY = (j - 1 > 0) && (j + 1 < malhaGerada.getNy());
                        conditionZ = (k - 1 > 0) && (k + 1 < malhaGerada.getNz());

                        if (conditionX && conditionY && conditionZ) {

                            conditionX = (malhaGerada.obterMaterialCubo(i - 1, j, k) != 1) && (malhaGerada.obterMaterialCubo(i + 1, j, k) != 1);
                            conditionY = (malhaGerada.obterMaterialCubo(i, j - 1, k) != 1) && (malhaGerada.obterMaterialCubo(i, j + 1, k) != 1);
                            conditionZ = (malhaGerada.obterMaterialCubo(i, j, k - 1) != 1) && (malhaGerada.obterMaterialCubo(i, j, k + 1) != 1);

                            if (conditionX && conditionY && conditionZ) {
                                number++;
                            } else {
                                //obtem a visibilidade do material
                                VisibilidadeMaterialVO vm = new VisibilidadeMaterialVO();
                                vm.setIdMaterial(idMaterial);
                                vm = materiais.get(materiais.indexOf(vm));

                                if (vm.isVisivel()){
                                    gl.glPolygonMode(gl.GL_FRONT_AND_BACK, gl.GL_FILL);
                                    // Obtém o Material do Cubo
                                    material = requisicaoServicos.obterMaterial(idMaterial);
                                    // Obtém a Cor do Material
                                    cor = material.getCor();
                                    // Seta a Cor no Cubo
                                    R = (float) (cor.getRed()) / (255);
                                    G = (float) (cor.getGreen()) / (255);
                                    B = (float) (cor.getBlue()) / (255);

                                    gl.glPushMatrix();
                                    gl.glColor4f(R, G, B, vm.getVisibilidade());
                                    glut.glutSolidCube(malhaGerada.getDx());
                                    gl.glPopMatrix();
                                    // Executa os comandos OpenGL
                                    gl.glFlush();
                                }
                            }
                        } else {
                            //obtem a visibilidade do material
                            VisibilidadeMaterialVO vm = new VisibilidadeMaterialVO();
                            vm.setIdMaterial(idMaterial);
                            vm = materiais.get(materiais.indexOf(vm));

                            if (vm.isVisivel()){
                                gl.glPolygonMode(gl.GL_FRONT_AND_BACK, gl.GL_FILL);
                                // Obtém o Material do Cubo
                                material = requisicaoServicos.obterMaterial(idMaterial);
                                // Obtém a Cor do Material
                                cor = material.getCor();
                                // Seta a Cor no Cubo
                                R = (float) (cor.getRed()) / (255);
                                G = (float) (cor.getGreen()) / (255);
                                B = (float) (cor.getBlue()) / (255);

                                gl.glPushMatrix();
                                gl.glColor4f(R, G, B, vm.getVisibilidade());
                                glut.glutSolidCube(malhaGerada.getDx());
                                gl.glPopMatrix();
                                // Executa os comandos OpenGL
                                gl.glFlush();
                            }
                        }

                    }
                    gl.glPopMatrix();
                }
            }
        }

        System.out.println("RenderizadorMalha: " + number + " cubos não foram impressos");

        gl.glEndList();
    }
     /**
     * Gera o Grid no GLCanvas
     */
    private void geraGrid() {
        listaGrid = gl.glGenLists(1);
        gl.glNewList(listaGrid,gl.GL_COMPILE);

        gl.glColor3f(0.0f, 0.0f, 0.0f);
        gl.glLineWidth(1.0f);

        int z = 0;

        // Desenha linhas verticais
        int y = tamGrid / 2;
        int x = -tamGrid / 2;
        gl.glBegin(GL.GL_LINES);
        for (x = -(tamGrid / 2); x <= tamGrid / 2; x++) {
            gl.glVertex3i(x, y, z);
            gl.glVertex3i(x, -y, z);
        }
        gl.glEnd();
        
        // Desenha linhas horizontais
        x = -tamGrid / 2;
        y = tamGrid / 2;
        gl.glBegin(GL.GL_LINES);
        for (y = -(tamGrid / 2); y <= tamGrid / 2; y++) {
            gl.glVertex3i(x, y, z);
            gl.glVertex3i(-x, y, z);
        }
        gl.glEnd();

        gl.glColor3f(255.0f, 0.0f, 0.0f);
        gl.glLineWidth(3.0f);
        gl.glBegin(GL.GL_LINES);
        gl.glVertex3f(0, 0, 0);
        gl.glVertex3f(5, 0, 0);
        gl.glEnd();
        gl.glRasterPos3f(4.5f, 0.5f, 0.5f);
        glut.glutBitmapCharacter(GLUT.BITMAP_TIMES_ROMAN_10, 'X');

        gl.glColor3f(0.0f, 255.0f, 0.0f);
        gl.glBegin(GL.GL_LINES);
        gl.glVertex3f(0, 0, 0);
        gl.glVertex3f(0, 5, 0);
        gl.glEnd();
        gl.glRasterPos3f(0.5f, 4.5f, 0.5f);
        glut.glutBitmapCharacter(GLUT.BITMAP_TIMES_ROMAN_10, 'Y');

        gl.glColor3f(0.0f, 0.0f, 255.0f);
        gl.glBegin(GL.GL_LINES);
        gl.glVertex3f(0, 0, 0);
        gl.glVertex3f(0, 0, 5);
        gl.glEnd();
        gl.glRasterPos3f(0.5f, 0.5f, 4.5f);
        glut.glutBitmapCharacter(GLUT.BITMAP_TIMES_ROMAN_10, 'Z');

        gl.glEndList();
    }
     /**
     * Gera o Grid do dominio computacional
     */
    private void geraGridDominio() {
        listaDominio = gl.glGenLists(1);
        gl.glNewList(listaDominio,gl.GL_COMPILE);

        gl.glColor3f(0.0f, 255.0f, 255.0f);
        gl.glLineWidth(2.0f);

        //eixo x
        gl.glBegin(GL.GL_LINES);
        gl.glVertex3f(malhaGerada.getXMin(), malhaGerada.getYMin(), malhaGerada.getZMin());
        gl.glVertex3f(malhaGerada.getXMax(), malhaGerada.getYMin(), malhaGerada.getZMin());
        gl.glEnd();

        //eixo x com y
        gl.glBegin(GL.GL_LINES);
        gl.glVertex3f(malhaGerada.getXMin(), malhaGerada.getYMax(), malhaGerada.getZMin());
        gl.glVertex3f(malhaGerada.getXMax(), malhaGerada.getYMax(), malhaGerada.getZMin());
        gl.glEnd();

        //eixo x com z
        gl.glBegin(GL.GL_LINES);
        gl.glVertex3f(malhaGerada.getXMin(), malhaGerada.getYMin(), malhaGerada.getZMax());
        gl.glVertex3f(malhaGerada.getXMax(), malhaGerada.getYMin(), malhaGerada.getZMax());
        gl.glEnd();

        //eixo x com z e y
        gl.glBegin(GL.GL_LINES);
        gl.glVertex3f(malhaGerada.getXMin(), malhaGerada.getYMax(), malhaGerada.getZMax());
        gl.glVertex3f(malhaGerada.getXMax(), malhaGerada.getYMax(), malhaGerada.getZMax());
        gl.glEnd();

        //eixo y
        gl.glBegin(GL.GL_LINES);
        gl.glVertex3f(malhaGerada.getXMin(), malhaGerada.getYMin(), malhaGerada.getZMin());
        gl.glVertex3f(malhaGerada.getXMin(), malhaGerada.getYMax(), malhaGerada.getZMin());
        gl.glEnd();

        //eixo y com x
        gl.glBegin(GL.GL_LINES);
        gl.glVertex3f(malhaGerada.getXMax(), malhaGerada.getYMin(), malhaGerada.getZMin());
        gl.glVertex3f(malhaGerada.getXMax(), malhaGerada.getYMax(), malhaGerada.getZMin());
        gl.glEnd();

        //eixo y com z
        gl.glBegin(GL.GL_LINES);
        gl.glVertex3f(malhaGerada.getXMin(), malhaGerada.getYMin(), malhaGerada.getZMax());
        gl.glVertex3f(malhaGerada.getXMin(), malhaGerada.getYMax(), malhaGerada.getZMax());
        gl.glEnd();

        //eixo y com z e y
        gl.glBegin(GL.GL_LINES);
        gl.glVertex3f(malhaGerada.getXMax(), malhaGerada.getYMin(), malhaGerada.getZMax());
        gl.glVertex3f(malhaGerada.getXMax(), malhaGerada.getYMax(), malhaGerada.getZMax());
        gl.glEnd();

        //eixo z
        gl.glBegin(GL.GL_LINES);
        gl.glVertex3f(malhaGerada.getXMin(), malhaGerada.getYMin(), malhaGerada.getZMin());
        gl.glVertex3f(malhaGerada.getXMin(), malhaGerada.getYMin(), malhaGerada.getZMax());
        gl.glEnd();

        //eixo z com x
        gl.glBegin(GL.GL_LINES);
        gl.glVertex3f(malhaGerada.getXMax(), malhaGerada.getYMin(), malhaGerada.getZMin());
        gl.glVertex3f(malhaGerada.getXMax(), malhaGerada.getYMin(), malhaGerada.getZMax());
        gl.glEnd();

        //eixo z com y
        gl.glBegin(GL.GL_LINES);
        gl.glVertex3f(malhaGerada.getXMin(), malhaGerada.getYMax(), malhaGerada.getZMin());
        gl.glVertex3f(malhaGerada.getXMin(), malhaGerada.getYMax(), malhaGerada.getZMax());
        gl.glEnd();

        //eixo z com x e y
        gl.glBegin(GL.GL_LINES);
        gl.glVertex3f(malhaGerada.getXMax(), malhaGerada.getYMax(), malhaGerada.getZMin());
        gl.glVertex3f(malhaGerada.getXMax(), malhaGerada.getYMax(), malhaGerada.getZMax());
        gl.glEnd();

        gl.glEndList();
    }
     /**
     * Gera a referencia dos cortes transversais
     */
    private void geraReferenciaCorte() {
        float valorMaximo = 0;
        float valorMinimo = 0;

        if (eixo.equals(Eixo.X)){
            valorMaximo = malhaGerada.getXMax();
            valorMinimo = malhaGerada.getXMin();
        }else if (eixo.equals(Eixo.Y)){
            valorMaximo = malhaGerada.getYMax();
            valorMinimo = malhaGerada.getYMin();
        }else if (eixo.equals(Eixo.Z)){
            valorMaximo = malhaGerada.getZMax();
            valorMinimo = malhaGerada.getZMin();
        }

        if (valor1 > valorMaximo) {
            valor1 = valorMaximo;
        } else if (valor1 < valorMinimo) {
            valor1 = valorMinimo;
        }
        if (valor2 > valorMaximo) {
            valor2 = valorMaximo;
        } else if (valor2 < valorMinimo) {
            valor2 = valorMinimo;
        }

        listaCorte = gl.glGenLists(1);
        gl.glNewList(listaCorte,gl.GL_COMPILE);

        if (statusPosicaoValidaMouse){
            gl.glColor4f(0.0f, 255.0f, 255.0f, 0.3f);
        }else{
            gl.glColor4f(255.0f, 0.0f, 0.0f, 0.3f);
        }
        gl.glLineWidth(1.0f);

        if (eixo.equals(Eixo.X)){
            //Corte 1
            gl.glBegin(GL.GL_QUADS);
            gl.glVertex3f(valor1, malhaGerada.getYMin(), malhaGerada.getZMax());
            gl.glVertex3f(valor1, malhaGerada.getYMax(), malhaGerada.getZMax());
            gl.glVertex3f(valor1, malhaGerada.getYMax(), malhaGerada.getZMin());
            gl.glVertex3f(valor1, malhaGerada.getYMin(), malhaGerada.getZMin());
            gl.glEnd();

            //Corte 2
            gl.glBegin(GL.GL_QUADS);
            gl.glVertex3f(valor2, malhaGerada.getYMin(), malhaGerada.getZMax());
            gl.glVertex3f(valor2, malhaGerada.getYMax(), malhaGerada.getZMax());
            gl.glVertex3f(valor2, malhaGerada.getYMax(), malhaGerada.getZMin());
            gl.glVertex3f(valor2, malhaGerada.getYMin(), malhaGerada.getZMin());
            gl.glEnd();
        }else if (eixo.equals(Eixo.Y)){
            //Corte 1
            gl.glBegin(GL.GL_QUADS);
            gl.glVertex3f(malhaGerada.getXMin(), valor1, malhaGerada.getZMax());
            gl.glVertex3f(malhaGerada.getXMax(), valor1, malhaGerada.getZMax());
            gl.glVertex3f(malhaGerada.getXMax(), valor1, malhaGerada.getZMin());
            gl.glVertex3f(malhaGerada.getXMin(), valor1, malhaGerada.getZMin());
            gl.glEnd();

            //Corte 2
            gl.glBegin(GL.GL_QUADS);
            gl.glVertex3f(malhaGerada.getXMin(), valor2, malhaGerada.getZMax());
            gl.glVertex3f(malhaGerada.getXMax(), valor2, malhaGerada.getZMax());
            gl.glVertex3f(malhaGerada.getXMax(), valor2, malhaGerada.getZMin());
            gl.glVertex3f(malhaGerada.getXMin(), valor2, malhaGerada.getZMin());
            gl.glEnd();
        }else if (eixo.equals(Eixo.Z)){
            //Corte 1
            gl.glBegin(GL.GL_QUADS);
            gl.glVertex3f(malhaGerada.getXMin(), malhaGerada.getYMin(), valor1);
            gl.glVertex3f(malhaGerada.getXMax(), malhaGerada.getYMin(), valor1);
            gl.glVertex3f(malhaGerada.getXMax(), malhaGerada.getYMax(), valor1);
            gl.glVertex3f(malhaGerada.getXMin(), malhaGerada.getYMax(), valor1);
            gl.glEnd();

            //Corte 2
            gl.glBegin(GL.GL_QUADS);
            gl.glVertex3f(malhaGerada.getXMin(), malhaGerada.getYMin(), valor2);
            gl.glVertex3f(malhaGerada.getXMax(), malhaGerada.getYMin(), valor2);
            gl.glVertex3f(malhaGerada.getXMax(), malhaGerada.getYMax(), valor2);
            gl.glVertex3f(malhaGerada.getXMin(), malhaGerada.getYMax(), valor2);
            gl.glEnd();
        }

        gl.glEndList();
    }

    public void keyPressed(KeyEvent e) {
        switch (e.getKeyChar()) {
            case 'x':
                addRotacaoX();
                break;
            case 'X':
                subRotacaoX();
                break;
            case 'y':
                addRotacaoY();
                break;
            case 'Y':
                subRotacaoY();
                break;
            case 'z':
                addRotacaoZ();
                break;
            case 'Z':
                subRotacaoZ();
                break;
            case '+':
                addPosicaoZ();
                break;
            case '-':
                subPosicaoZ();
                break;
            case 'w':
                addPosicaoY();
                break;
            case 'W':
                addPosicaoY();
                break;
            case 's':
                subPosicaoY();
                break;
            case 'S':
                subPosicaoY();
                break;
            case 'd':
                addPosicaoX();
                break;
            case 'D':
                addPosicaoX();
                break;
            case 'a':
                subPosicaoX();
                break;
            case 'A':
                subPosicaoX();
                break;
            case 'g':
                setStatusGrid(!isStatusGrid());
                break;
            case 'G':
                setStatusGrid(!isStatusGrid());
                break;
            case 'r':
                resetValues();
                break;
            case 'R':
                resetValues();
                break;
        }
    }

    public void keyReleased(KeyEvent e) {
//        System.out.println("keyReleased: " + e.getKeyChar());
    }

    public void keyTyped(KeyEvent e) {
//        System.out.println("keyTyped: " + e.getKeyChar());
    }

    public void mouseClicked(MouseEvent e) {
        if (statusCorteComMouse){
            if (e.getButton() == MouseEvent.BUTTON1){
                if (valorAtual == 1){
                    valorAtual = 2;
                }else if (valorAtual == 2){
                    statusCorteComMouse = false;
                    statusCorteReferencia = false;
                }

                if (this.eixo.equals(Eixo.X)) {
                    geraCorteTransversal(valor1, valor2, dominioY1, dominioY2, dominioZ1, dominioZ2);
                } else if (this.eixo.equals(Eixo.Y)) {
                    geraCorteTransversal(dominioX1, dominioX2, valor1, valor2, dominioZ1, dominioZ2);
                } else if (this.eixo.equals(Eixo.Z)) {
                    geraCorteTransversal(dominioX1, dominioX2, dominioY1, dominioY2, valor1, valor2);
                }
            }else if (e.getButton() == MouseEvent.BUTTON3){
                statusCorteComMouse = false;
            }
        }
    }

    public void mouseEntered(MouseEvent e) {
//        System.out.println("mouseEntered");
    }

    public void mouseExited(MouseEvent e) {
//        System.out.println("mouseExited");
    }

    public void mousePressed(MouseEvent e) {
//        System.out.println("mousePressed");
    }

    public void mouseReleased(MouseEvent e) {
//        System.out.println("mouseReleased");
    }

    public void mouseDragged(MouseEvent e) {
//        System.out.println("mouseDragged");
    }

    public void mouseMoved(MouseEvent e) {
        if (statusCorteComMouse){
            alteraReferenciaCorteTransversal(e, eixo);
        }
    }

    public void mouseWheelMoved(MouseWheelEvent e) {
        if (e.getWheelRotation() == -1) {
            addPosicaoZ();
        } else {
            subPosicaoZ();
        }
    }

    /**
     * Rotaciona o eixo X em uma unidade positiva
     */
    public void addRotacaoX(){
        if (!statusCorteComMouse || rotacaoX < rotacaoXMaximaCorte){
            rotacaoX += ROTACAO_STEP;
            gLCanvas.display();
        }
    }
    /**
     * Rotaciona o eixo X em uma unidade negativa
     */
    public void subRotacaoX(){
        if (!statusCorteComMouse || rotacaoX > rotacaoXMinimaCorte){
            rotacaoX -= ROTACAO_STEP;
            gLCanvas.display();
        }
    }
    /**
     * Rotaciona o eixo Y em uma unidade positiva
     */
    public void addRotacaoY(){
        if (!statusCorteComMouse || rotacaoY < rotacaoYMaximaCorte){
            rotacaoY += ROTACAO_STEP;
            gLCanvas.display();
        }
    }
    /**
     * Rotaciona o eixo Y em uma unidade negativa
     */
    public void subRotacaoY(){
        if (!statusCorteComMouse || rotacaoY > rotacaoYMinimaCorte){
            rotacaoY -= ROTACAO_STEP;
            gLCanvas.display();
        }
    }
    /**
     * Rotaciona o eixo Z em uma unidade positiva
     */
    public void addRotacaoZ(){
        if (!statusCorteComMouse || rotacaoZ < rotacaoZMaximaCorte){
            rotacaoZ += ROTACAO_STEP;
            gLCanvas.display();
        }
    }
    /**
     * Rotaciona o eixo Z em uma unidade negativa
     */
    public void subRotacaoZ(){
        if (!statusCorteComMouse || rotacaoZ > rotacaoZMinimaCorte){
            rotacaoZ -= ROTACAO_STEP;
            gLCanvas.display();
        }
    }    
    /**
     * Translada o eixo X em uma unidade positiva
     */
    public void addPosicaoX(){
        if (!statusCorteComMouse || posicaoX < posicaoXMaximaCorte){
            posicaoX += POSICAO_STEP;
            gLCanvas.display();
        }
    }
    /**
     * Translada o eixo X em uma unidade negativa
     */
    public void subPosicaoX(){
        if (!statusCorteComMouse || posicaoX > posicaoXMinimaCorte){
            posicaoX -= POSICAO_STEP;
            gLCanvas.display();
        }
    }
    /**
     * Translada o eixo Y em uma unidade positiva
     */
    public void addPosicaoY(){
        if (!statusCorteComMouse || posicaoY < posicaoYMaximaCorte){
            posicaoY += POSICAO_STEP;
            gLCanvas.display();
        }
    }
    /**
     * Translada o eixo Y em uma unidade negativa
     */
    public void subPosicaoY(){
        if (!statusCorteComMouse || posicaoY > posicaoYMinimaCorte){
            posicaoY -= POSICAO_STEP;
            gLCanvas.display();
        }
    }
    /**
     * Translada o eixo Z em uma unidade positiva
     */
    public void addPosicaoZ(){
        if (!statusCorteComMouse || posicaoZ < posicaoZMaximaCorte){
            posicaoZ += ZOOM_STEP;
            gLCanvas.display();
        }
    }
    /**
     * Translada o eixo Z em uma unidade negativa
     */
    public void subPosicaoZ(){
        if (!statusCorteComMouse || posicaoZ > posicaoZMinimaCorte){
            posicaoZ -= ZOOM_STEP;
            gLCanvas.display();
        }
    }
    /**
     * Visibilida da grid
     */
    public boolean isStatusGrid() {
        return statusGrid;
    }
    public void setStatusGrid(boolean statusGrid) {
        this.statusGrid = statusGrid;
        gLCanvas.display();
    }
    /**
     * Visibilida da grid do dominio
     */
    public boolean isStatusGridDominio() {
        return statusGridDominio;
    }
    public void setStatusGridDominio(boolean statusGridDominio) {
        this.statusGridDominio = statusGridDominio;
        gLCanvas.display();
    }
    /**
     * Visibilida da "linha" onde será feito o corte
     */
    public boolean isStatusCorteReferencia() {
        return statusCorteReferencia;
    }
    public void setStatusCorteReferencia(boolean statusCorteReferencia) {
        this.statusCorteReferencia = statusCorteReferencia;
        this.statusPosicaoValidaMouse = true;
        gLCanvas.display();
    }
    /**
     * Corte na malha com o mouse habilitado/desabilitado
     */
    public boolean isStatusCorteComMouse() {
        return statusCorteComMouse;
    }
    public void setStatusCorteComMouse(boolean statusCorteComMouse, Eixo e) {
        this.statusCorteComMouse = statusCorteComMouse;

        if (statusCorteComMouse){
            valorAtual = 1;
            if (e != null){
                if (e.equals(Eixo.X)){
                    valor1 = dominioX1;
                    valor2 = dominioX2;
                    //Limites da rotação
                    rotacaoXMaximaCorte =   0.0f;
                    rotacaoXMinimaCorte = -85.0f;
                    rotacaoYMaximaCorte =  45.0f;
                    rotacaoYMinimaCorte = -45.0f;
                    rotacaoZMaximaCorte =  45.0f;
                    rotacaoZMinimaCorte = -45.0f;
                    //Limites do translado
                    posicaoXMaximaCorte =  32.0f;
                    posicaoXMinimaCorte = -32.0f;
                    posicaoYMaximaCorte =  32.0f;
                    posicaoYMinimaCorte =   0.0f;
                    posicaoZMaximaCorte =  -1.0f;
                    posicaoZMinimaCorte = -98.0f;
                    //Valores iniciais
                    RotacaoInicialX = -70.0f;
                    RotacaoInicialY =   0.0f;
                    RotacaoInicialZ =   0.0f;
                    PosicaoInicialX =   0.0f;
                    PosicaoInicialY =   0.0f;
                    PosicaoInicialZ = -40.0f;
                }else if (e.equals(Eixo.Y)){
                    valor1 = dominioY1;
                    valor2 = dominioY2;
                    //Limites da rotação
                    rotacaoXMaximaCorte =   0.0f;
                    rotacaoXMinimaCorte = -85.0f;
                    rotacaoYMaximaCorte =  45.0f;
                    rotacaoYMinimaCorte = -45.0f;
                    rotacaoZMaximaCorte = 135.0f;
                    rotacaoZMinimaCorte =  45.0f;
                    //Limites do translado
                    posicaoXMaximaCorte =  32.0f;
                    posicaoXMinimaCorte = -32.0f;
                    posicaoYMaximaCorte =  32.0f;
                    posicaoYMinimaCorte =   0.0f;
                    posicaoZMaximaCorte =  -1.0f;
                    posicaoZMinimaCorte = -98.0f;
                    //Valores iniciais
                    RotacaoInicialX = -70.0f;
                    RotacaoInicialY =   0.0f;
                    RotacaoInicialZ =  90.0f;
                    PosicaoInicialX =   0.0f;
                    PosicaoInicialY =   0.0f;
                    PosicaoInicialZ = -40.0f;
                }else if (e.equals(Eixo.Z)){
                    valor1 = dominioZ1;
                    valor2 = dominioZ2;
                    //Limites da rotação
                    rotacaoXMaximaCorte = -45.0f;
                    rotacaoXMinimaCorte = -135.0f;
                    rotacaoYMaximaCorte =  45.0f;
                    rotacaoYMinimaCorte = -45.0f;
                    rotacaoZMaximaCorte =  45.0f;
                    rotacaoZMinimaCorte = -45.0f;
                    //Limites da rotação
                    posicaoXMaximaCorte =  32.0f;
                    posicaoXMinimaCorte = -32.0f;
                    posicaoYMaximaCorte =  32.0f;
                    posicaoYMinimaCorte =  32.0f;
                    posicaoZMaximaCorte =  -1.0f;
                    posicaoZMinimaCorte = -98.0f;
                    //Valores iniciais
                    RotacaoInicialX = -70.0f;
                    RotacaoInicialY =   0.0f;
                    RotacaoInicialZ =   0.0f;
                    PosicaoInicialX =   0.0f;
                    PosicaoInicialY =   0.0f;
                    PosicaoInicialZ = -40.0f;
                }
                //Coloca a cena no valor inicial para o local onde será feito o corte
                rotacaoX = RotacaoInicialX;
                rotacaoY = RotacaoInicialY;
                rotacaoZ = RotacaoInicialZ;
                posicaoX = PosicaoInicialX;
                posicaoY = PosicaoInicialY;
                posicaoZ = PosicaoInicialZ;

                corteReferenciaAlterado = true;
                this.eixo = e;
            }
        }else{
            RotacaoInicialX = -70.0f;
            RotacaoInicialY =   0.0f;
            RotacaoInicialZ =   0.0f;
            PosicaoInicialX =   0.0f;
            PosicaoInicialY =   0.0f;
            PosicaoInicialZ = -40.0f;
        }
        setStatusCorteReferencia(statusCorteComMouse);
    }
    /**
     * Retorna o eixo onde o corte será feito
     */
    public Eixo getEixo() {
        return eixo;
    }
    /**
     * Retorna as configurações padrões da cena
     */
    public void resetValues(){
        rotacaoX = RotacaoInicialX;
        rotacaoY = RotacaoInicialY;
        rotacaoZ = RotacaoInicialZ;
        posicaoX = PosicaoInicialX;
        posicaoY = PosicaoInicialY;
        posicaoZ = PosicaoInicialZ;
        statusGrid = STATUS_GRID_INICIAL;
        gLCanvas.display();
    }

    public InterfaceRenderizacaoMalha getMalhaGerada(){
        return this.malhaGerada;
    }

    public List<VisibilidadeMaterialVO> getMateriais() {
        if (materiais == null){
            if (malhaGerada != null){
                // Obtém a relação de todos materiais da malha
                materiais = new ArrayList<VisibilidadeMaterialVO>();
                for (int k = 0; k < malhaGerada.getNz(); k++) {
                    for (int j = 0; j < malhaGerada.getNy(); j++) {
                        for (int i = 0; i < malhaGerada.getNx(); i++) {
                            int idMaterial = malhaGerada.obterMaterialCubo(i, j, k);
                            // Diferente de ar
                            if (idMaterial != 1){
                                VisibilidadeMaterialVO vmVO = new VisibilidadeMaterialVO();
                                vmVO.setIdMaterial(idMaterial);
                                if (!materiais.contains(vmVO)){
                                    Material material = requisicaoServicos.obterMaterial(idMaterial);
                                    vmVO.setNomeMaterial(material.getNome());
                                    vmVO.setVisivel(true);
                                    materiais.add(vmVO);
                                }
                            }
                        }
                    }
                }
            }
        }

        return materiais;
    }

    public float getDominioX1() {
        return dominioX1;
    }
    public float getDominioX2() {
        return dominioX2;
    }
    public float getDominioY1() {
        return dominioY1;
    }
    public float getDominioY2() {
        return dominioY2;
    }
    public float getDominioZ1() {
        return dominioZ1;
    }
    public float getDominioZ2() {
        return dominioZ2;
    }

    
    public float getValor1() {
        return valor1;
    }
    public float getValor2() {
        return valor2;
    }


}
